package
{
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;

	public class QuadTreeNode
	{
		public var rect:Rectangle;
		public var children:Vector.<QuadTreeNode>;
		public var objects:Vector.<ISpatialIndexable>;
		
		public function QuadTreeNode(rect:Rectangle)
		{
			objects = new Vector.<ISpatialIndexable>;
			children = new Vector.<QuadTreeNode>;
			this.rect = rect;
		}
		
		public function getDisplay():Sprite{
			var spr:Sprite = Util.getRect(rect.width * Global.PPU,rect.height * Global.PPU, 0x00ff00,2);

			for each(var child:QuadTreeNode in children){
				var childSprite:Sprite = child.getDisplay()
				spr.addChild(childSprite);
				childSprite.x = child.rect.x * Global.PPU - rect.x * Global.PPU;
				childSprite.y = child.rect.y * Global.PPU - rect.y * Global.PPU;
			}
			
			return spr;
		}
		
		public function createChildren():void{
			var i:int, j:int;
			var node:QuadTreeNode;
			var x:Number, y:Number, width:Number, height:Number;
			
			for(i = 0; i < 2; i++){
				for(j = 0; j < 2; j++){
					x = rect.x + i * rect.width/2;
					y = rect.y + j * rect.height/2;
					width = rect.width/2;
					height = rect.height/2;
					
					node = new QuadTreeNode(new Rectangle(x, y, width, height));
					children.push(node);
				}
			}
		}
		
		public function add(entity:ISpatialIndexable, depth:int):void{
			if(children.length == 0){
				createChildren();
			}

			var foundContainingChild:Boolean = false;
			for each(var child:QuadTreeNode in children){
				if(child.rect.containsRect(entity.getRect())){
					child.add(entity,depth + 1);
					foundContainingChild = true;
				}
			}
			
			if(foundContainingChild == false){
				objects.push(entity);
			}
		}
		
		public function remove(entity:ISpatialIndexable, depth:int):void{
			var foundContainingChild:Boolean = false;
			for each(var child:QuadTreeNode in children){
				if(child.rect.containsRect(entity.getRect())){
					child.remove(entity,depth + 1);
					foundContainingChild = true;
				}
			}
			
			var i:int, il:int;
			for(i = 0; i < objects.length; i++){
				if(objects[i].getRect().equals(entity.getRect())){
					objects.splice(i,1);
				}
			}	
		}
		
		public function find(entity:ISpatialIndexable):Boolean{
			var foundContainingChild:Boolean = false;
			
			for each(var child:QuadTreeNode in children){
				if(child.rect.containsRect(entity.getRect())){
					return child.find(entity);
				}
			}
			
			var i:int, il:int;
			for(i = 0, il = objects.length; i < il; i++){
				if(objects[i].getRect().equals(entity.getRect())){
					return true;
				}
			}
			
			return false;	
		}
		
		public function getPointCollisions(pnt:Point, collisions:Vector.<ISpatialIndexable>):void{						
			for each(var obj:ISpatialIndexable in objects){
				if(obj.getRect().containsPoint(pnt)){
					collisions.push(obj);
				}
			}
			
			for each(var child:QuadTreeNode in children){
				if(child.rect.contains(pnt.x, pnt.y)){
					child.getPointCollisions(pnt, collisions);
				}
			}
		}
		
		public function getRectCollisions(rect:Rectangle, collisions:Vector.<ISpatialIndexable>):void{
			for each(var obj:ISpatialIndexable in objects){
				if(obj.getRect().intersects(rect)){
					collisions.push(obj);
				}
			}
			
			for each(var child:QuadTreeNode in children){
				if(child.rect.intersects(rect)){
					child.getRectCollisions(rect, collisions);
				}
			}
		}		
	}
}